﻿using System;
using System.Drawing;
using System.Windows.Forms;
using dk.Helper.Base;

namespace dk.Helper.Controls
{
    public partial class AttacksPlannerForm : Form
    {
        private readonly IAttacksPlanner attacksPlanner;
        private readonly IWorld world;

        /// <summary>
        /// Initializes a new instance of the <see cref="AttacksPlannerForm"/> class.
        /// </summary>
        /// <param name="world">The world.</param>
        /// <param name="attacksPlanner">The attacks planner.</param>
        public AttacksPlannerForm(IWorld world, IAttacksPlanner attacksPlanner)
        {
            this.world = world;
            this.attacksPlanner = attacksPlanner;
            this.attacksPlanner.AttacksChanged += AttacksPlanner_AttacksChanged;
            InitializeComponent();
        }

        /// <summary>
        /// Handles the AttacksChanged event of the AttacksPlanner control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void AttacksPlanner_AttacksChanged(object sender, EventArgs e)
        {
            SuspendLayout();
            UpdateDataGridView();
            treeAttacks.Nodes.Clear();
            Activate();
            ResumeLayout();
        }

        /// <summary>
        /// Updates the data grid view.
        /// </summary>
        private void UpdateDataGridView()
        {
            Cursor.Current = Cursors.WaitCursor;
            dgvAttacks.Rows.Clear();
            foreach (IAttack attack in attacksPlanner.Attacks)
            {
                int i = dgvAttacks.Rows.Add();
                DataGridViewRow row = dgvAttacks.Rows[i];
                UpdateRow(row, attack);
            }
            Cursor.Current = Cursors.Default;
        }

        /// <summary>
        /// Updates the row.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <param name="attack">The attack.</param>
        private void UpdateRow(DataGridViewRow row, IAttack attack)
        {
            if (row.Index < 0) return;
            row.Cells["clmAttack"].Value = attack;
            row.Cells["clmFrom"].Value = attack.From.ToString();
            row.Cells["clmTo"].Value = attack.To.ToString();
            row.Cells["clmToPoints"].Value = attack.To.Points;
            row.Cells["clmLaunchTime"].Value = attack.Start;
            row.Cells["clmLandTime"].Value = attack.End;
            row.Cells["clmDuration"].Value = attack.Duration;
            row.Cells["clmDescription"].Value = attack.Description;
            row.DefaultCellStyle.Font = attack.IsNoble
                                            ? new Font(dgvAttacks.DefaultCellStyle.Font, FontStyle.Bold)
                                            : new Font(dgvAttacks.DefaultCellStyle.Font, FontStyle.Regular);
            row.Visible = !attack.IsOld;
        }

        private void btnSetLaunchTime_Click(object sender, EventArgs e)
        {
            if (dgvAttacks.SelectedRows.Count == 0) return;
            foreach (DataGridViewRow row in dgvAttacks.SelectedRows)
            {
                var attack = (IAttack) row.Cells["clmAttack"].Value;
                attack.Start = dtpLaunchTime.Value;
                UpdateRow(row, attack);
            }
        }

        private void btnSetLandTime_Click(object sender, EventArgs e)
        {
            if (dgvAttacks.SelectedRows.Count == 0) return;
            foreach (DataGridViewRow row in dgvAttacks.SelectedRows)
            {
                IAttack attack = GetAttack(row);
                if (attack != null)
                {
                    attack.End = dtpLandTime.Value;
                    UpdateRow(row, attack);
                }
            }
        }

        private IAttack GetAttack(DataGridViewRow row)
        {
            if (row.Index < 0) return null;
            return (IAttack) row.Cells["clmAttack"].Value;
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            DataGridViewSelectedRowCollection selectedRows = dgvAttacks.SelectedRows;
            if (selectedRows.Count == 0) return;
            for (int index = 0; index < selectedRows.Count; index++)
            {
                DataGridViewRow row = selectedRows[index];
                attacksPlanner.RemoveAttack(GetAttack(row));
                if (dgvAttacks.Rows.Contains(row))
                    dgvAttacks.Rows.Remove(row);
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            TickDataGridUpdate();
            TickTreeUpdate();
        }

        private void TickDataGridUpdate()
        {
            for (int i = 0; i < dgvAttacks.Rows.Count; i++)
            {
                DataGridViewRow row = dgvAttacks.Rows[i];
                IAttack attack = GetAttack(row);
                if (attack == null) continue;
                if (attack.IsOld)
                {
                    row.Visible = false;
                }
                else
                {
                    if (!row.Displayed) continue;
                    if (!row.Visible) row.Visible = true;
                    TimeSpan span = attack.Start - DateTime.Now;
                    row.Cells["clmRemainingTime"].Value = span.ToString(@"hh\:mm\:ss");
                }
            }
            lblAttacksCount.Text = dgvAttacks.Rows.Count.ToString();
        }

        private void TickTreeUpdate()
        {
            treeAttacks.BeginUpdate();
            foreach (IAttack attack in attacksPlanner.Attacks)
            {
                IPlayer target = world.Players.PlayersByID[attack.To.PlayerID];
                TreeNode targetPlayerNode;
                if (!treeAttacks.Nodes.ContainsKey(target.Name))
                {
                    targetPlayerNode = new TreeNode();
                    targetPlayerNode.Name = target.Name;
                    treeAttacks.Nodes.Add(targetPlayerNode);
                }
                targetPlayerNode = treeAttacks.Nodes[target.Name];
                targetPlayerNode.Text = GetTargetPlayerNodeText(target);
                TreeNode toVillageNode;
                if (!targetPlayerNode.Nodes.ContainsKey(attack.To.ID.ToString()) && !attack.IsOld)
                {
                    toVillageNode = new TreeNode();
                    toVillageNode.Name = attack.To.ID.ToString();
                    toVillageNode.Text = attack.To.ToString();
                    targetPlayerNode.Nodes.Add(toVillageNode);
                }
                toVillageNode = targetPlayerNode.Nodes[attack.To.ID.ToString()];
                if (toVillageNode == null) continue;
                if (!toVillageNode.Nodes.ContainsKey(attack.From.ID.ToString()) && !attack.IsOld)
                {
                    var fromVillageNode = new TreeNode();
                    SetFromVillageNode(attack, fromVillageNode);
                    toVillageNode.Nodes.Add(fromVillageNode);
                    toVillageNode.Text = GetToVillageNodeText(attack, toVillageNode);
                }
                if (toVillageNode.Nodes.ContainsKey(attack.From.ID.ToString()) && attack.IsOld)
                {
                    TreeNode fromVillageNode = toVillageNode.Nodes[attack.From.ID.ToString()];
                    fromVillageNode.Remove();
                    toVillageNode.Text = GetToVillageNodeText(attack, toVillageNode);
                    if (toVillageNode.Nodes.Count == 0)
                        toVillageNode.Remove();
                }
            }
            treeAttacks.EndUpdate();
        }

        private string GetTargetPlayerNodeText(IPlayer target)
        {
            return target.Name;
        }

        private void SetFromVillageNode(IAttack attack, TreeNode fromVillageNode)
        {
            fromVillageNode.Name = attack.From.ID.ToString();
            fromVillageNode.Text = attack.From.ToString();
            if (attack.IsFake)
                fromVillageNode.ForeColor = Color.DarkGray;
            if (attack.IsSupport)
                fromVillageNode.ForeColor = Color.DarkGreen;
            if (attack.IsNoble)
                fromVillageNode.NodeFont = new Font(
                    treeAttacks.Font.FontFamily,
                    treeAttacks.Font.Size,
                    FontStyle.Bold);
        }

        private string GetToVillageNodeText(IAttack attack, TreeNode toVillageNode)
        {
            string text = string.Empty;
            text += "[" + toVillageNode.Nodes.Count + "] ";
            text += attack.To.ToString();
            return text;
        }

        private void btnSetClearingAttack_Click(object sender, EventArgs e)
        {
            if (dgvAttacks.SelectedRows.Count == 0) return;
            foreach (DataGridViewRow row in dgvAttacks.SelectedRows)
            {
                if (row.Index < 0) continue;
                var attack = (IAttack) row.Cells["clmAttack"].Value;
                attack.IsClearing = true;
                attack.IsFake = false;
                attack.IsSupport = false;
                attack.IsNoble = false;
                attack.Description = "čistiaci útok";
                attack.UnitSpeed = 30;
                UpdateRow(row, attack);
            }
        }

        private void btnSetFakeAttack_Click(object sender, EventArgs e)
        {
            if (dgvAttacks.SelectedRows.Count == 0) return;
            foreach (DataGridViewRow row in dgvAttacks.SelectedRows)
            {
                if (row.Index < 0) continue;
                var attack = (IAttack) row.Cells["clmAttack"].Value;
                attack.IsClearing = false;
                attack.IsFake = true;
                attack.IsSupport = false;
                attack.IsNoble = false;
                attack.Description = "fake útok";
                attack.UnitSpeed = 30;
                UpdateRow(row, attack);
            }
        }

        private void btnSetSupportAttack_Click(object sender, EventArgs e)
        {
            if (dgvAttacks.SelectedRows.Count == 0) return;
            foreach (DataGridViewRow row in dgvAttacks.SelectedRows)
            {
                if (row.Index < 0) continue;
                var attack = (IAttack) row.Cells["clmAttack"].Value;
                attack.IsClearing = false;
                attack.IsFake = false;
                attack.IsSupport = true;
                attack.IsNoble = false;
                attack.Description = "podpora";
                attack.UnitSpeed = 30;
                UpdateRow(row, attack);
            }
        }

        private void btnSetNobleAttack_Click(object sender, EventArgs e)
        {
            if (dgvAttacks.SelectedRows.Count == 0) return;
            foreach (DataGridViewRow row in dgvAttacks.SelectedRows)
            {
                if (row.Index < 0) continue;
                var attack = (IAttack) row.Cells["clmAttack"].Value;
                attack.IsClearing = false;
                attack.IsFake = false;
                attack.IsSupport = false;
                attack.IsNoble = true;
                attack.Description = "šľachta";
                attack.UnitSpeed = 35;
                UpdateRow(row, attack);
            }
        }
    }
}